package br.edu.unifei.mestrado.fm;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Bucket {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * Valor do gain associado a cada vertice. ou melhor: lista de vertices associados a cada gain.
	 * 
	 * valor_gain | vertice | vertice
	 */
	private TreeMap<Integer, Map<Long, Cell>> map = new TreeMap<Integer, Map<Long, Cell>>(
			new Comparator<Integer>() {
				@Override
				public int compare(Integer o1, Integer o2) {
					return o1.compareTo(o2);
				}
			});

	private Map<Long, Integer> gainMap = new HashMap<Long, Integer>();

	public Set<Long> getVerticesWithGain(int gain) {
		return map.get(gain).keySet();
	}

	public Collection<Cell> getVerticesWithMaxGain() {
		return map.get(getMaxGain()).values();
	}

	public Collection<Cell> getVerticesWithMinGain() {
		return map.get(getMinGain()).values();
	}

	public void updateGainForNode(int newGain, int oldGain, Cell node) {
		removeNodeWithGain(oldGain, node);
		insertGainForNode(newGain, node);
	}

	public void insertGainForNode(int gain, Cell node) {
		Map<Long, Cell> nodes = map.get(gain);
		if (nodes == null) {
			nodes = new HashMap<Long, Cell>();
			map.put(gain, nodes);
		}
		nodes.put(node.getId(), node);
		gainMap.put(node.getId(), gain);
	}

	public void removeNodeWithGain(int gain, Cell node) {
		Map<Long, Cell> nodes = map.get(gain);
		if (nodes != null) {
			if (nodes.containsKey(node)) {
				nodes.remove(node.getId());
				if (nodes.size() == 0) {
					map.remove(gain);
				}
				return;
			}
			throw new RuntimeException("Node " + node + " não encontrado com gain " + gain + " GainMap: "
					+ map);
		}
		throw new RuntimeException("gain " + gain + " não encontrado");
	}

	public Integer getMinGain() {
		if (map.isEmpty()) {
			return null;
		}
		return map.firstKey();
	}

	public Integer getMaxGain() {
		if (map.isEmpty()) {
			return null;
		}
		return map.lastKey();
	}

	public Set<Integer> getGainList() {
		return map.keySet();
	}

	public Integer getGainOfNode(Long nodeId) {
		return gainMap.get(nodeId);
	}

	public void print(String bucketName) {
		logger.debug("{} {}", bucketName, new Object() {
			@Override
			public String toString() {
				StringBuffer b = new StringBuffer();
				for (Integer gain : map.keySet()) {
					b.append("G " + gain + ": ");
					for (Cell cell : map.get(gain).values()) {
						b.append(cell.getId() + ", ");
					}
				}
				return b.toString();
			}
		});
	}
}
